import sys, os
import struct
from pickle import loads
import time
from threading import Thread, Lock

sys.path.append(os.path.join(os.path.dirname(__file__), ".."))

from bitbrook.utilities.limited_socket import LSocket

class TrackerManager(Thread):
    def __init__(self, tracker_ip, tracker_port, brook_id, peer_port):
        super(TrackerManager, self).__init__()
        #needed for thread stopping
        self._shutdown = False
        self._shutdown_signal = Lock()
        
        self._tracker_ip = tracker_ip
        self._tracker_port = tracker_port
        self._brook_id = brook_id
        self._peer_port = peer_port
    
    def run(self):
        self._register_at_tracker()
        with self._shutdown_signal:
            faster_shutdown_hack = 0
            while not self._shutdown:
                if faster_shutdown_hack == 20:
                    self.send_update()
                    faster_shutdown_hack = 0
                else:
                    time.sleep(10)
                    faster_shutdown_hack = faster_shutdown_hack + 1
        

    def request_peers(self):
        self.connect_to_tracker()
        self.send(self.tracker, struct.pack("!16s40sH", "PEER REQUEST", self._brook_id, self._peer_port))
        try:
            return loads(self.tracker.recv(1024))
        except:
            return None
        self.tracker.close()
    
    def _register_at_tracker(self):
        self.connect_to_tracker()
        self.send(self.tracker, struct.pack("!16s40sH", "REGISTER", self._brook_id, self._peer_port))
        answer = self.tracker.recv(1024)
        print "Registering at the tracker. Response: ", answer     
        if answer[:4] == "NACK":
            print "Brook already registered with the tracker, requesting peers."
            self.send(self.tracker, struct.pack("!16s40sH", "PEER REQUEST", self._brook_id, self._peer_port))
            answer = self.tracker.recv(1024)
        self.tracker.close()
    
    def leave_tracker(self):
        self.connect_to_tracker()
        self.runs = False
        self.send(self.tracker, struct.pack("!16s40sH", "LEAVE", self._brook_id, self._peer_port))
        answer = self.tracker.recv(1024)
        self.tracker.close()
        print 'Leaving tracker. Response: ', answer
        
    def send_update(self):
        self.connect_to_tracker()
        self.send(self.tracker, struct.pack("!16s40sH", "UPDATE", self._brook_id, self._peer_port))
        answer = self.tracker.recv(1024)
        print "UPDATE: ", answer
        self.tracker.close()
    
    def send(self, sock, msg):
        send = 0
        while send < len(msg):
            send = send + sock.send(msg[send:])
    
    def connect_to_tracker(self):
        self.tracker = LSocket()
        self.tracker.connect((self._tracker_ip, self._tracker_port))

    def shutdown(self, block = True):
        print "Shutting down Tracker Manager"
        self._shutdown = True
        self.leave_tracker()
        if block:
            self._shutdown_signal.acquire()
            self._shutdown_signal.release()